import {normalize} from 'normalizr'
//import { handleDispatchError } from '../actions/other'
import {ADD_ENTITIES} from '../../constants/ActionTypes'
// Extracts the meta from API response.
const getMeta = response => {
  const meta = response['meta']
  if (!meta) {
    return {}
  }
  return meta
}
// Fetches an API response and normalizes the result JSON according to schema.
// This makes every API response have the same shape, regardless of how nested it was.
const callApi = (api, schema) => {

  return api.then(json => {
      const camelizedJson = json.data
      const meta = getMeta(json)
      return Object.assign({}, normalize(camelizedJson, schema), {meta: meta})
    }
  )
}

// Action key that carries API call info interpreted by this Redux middleware.
export const CALL_API = 'Call API'

// A Redux middleware that interprets actions with CALL_API info specified.
// Performs the call and promises when such actions are dispatched.
export default store => next => action => {
  const callAPI = action[CALL_API]
  if (typeof callAPI === 'undefined') {
    return next(action)
  }

  const {api, schema, types, isAdd, singlePage, callback} = callAPI

  if (!schema) {
    throw new Error('Specify one of the exported Schemas.')
  }

  const actionWith = data => {
    const finalAction = Object.assign({}, action, data)
    delete finalAction[CALL_API]
    return finalAction
  }

  const {REQUEST, SUCCESS, FAILURE, ADD} = types
  next(actionWith({type: REQUEST}))

  return callApi(api, schema).then(
    response => {

      store.dispatch({
        type: ADD_ENTITIES,
        ...response,
      })
      if (isAdd) {
        next(actionWith({
          response,
          type: ADD,
        }))
      } else {
        next(actionWith({
          response,
          singlePage,
          type: SUCCESS
        }))
      }
      if (callback) {
        return store.dispatch(callback)
      }
    },
    error => {
      //store.dispatch(handleDispatchError(error))
      next(actionWith({
        type: FAILURE,
        error: error.message || 'Something bad happened'
      }))
    }
  )
}
